import treeReduce from '../treeReduce';
import formulaResolver, { RESOLVER_NAME } from '../formulaResolver';
import { UNIT, unitAdd as unitMinus, unitAdd, unitDivide, unitMultiply } from './baseCal';

const { conditionResolver } = formulaResolver.resolver;

/**
 * 根据节点计算单位
 * @param node
 * @returns {string|*|string}
 */
const getUnitFromStack = node => {
    if (typeof node === 'string') {
        return node;
    }

    if (node.name === RESOLVER_NAME.CONDITION) {
        const conditions = conditionResolver.context || [];
        const key = conditionResolver.getKey(node);
        const matchCondition = conditions.find(condition => condition.value === key);
        return matchCondition ? matchCondition.unit : UNIT.CONSTANT;
    }

    return UNIT.CONSTANT;
};

const priortiy = {
    '(': 0,
    ')': 0,
    '+': 1,
    '-': 1,
    '*': 2,
    '/': 2
};

/**
 * 将公式树转换成后缀表达式
 * @param formulaTree
 * @returns {[]|boolean|*}
 */
const treeToPostfix = formulaTree => {
    const result = treeReduce(
        formulaTree,
        (accumulator, node, afterTrigger) => {
            const { stack, postfix } = accumulator;
            // 如果是操作符
            if (node.name === RESOLVER_NAME.OPERATOR) {
                if (stack.length > 0) {
                    while (
                        stack.length > 0 &&
                        priortiy[node.value] <= priortiy[stack[stack.length - 1].value] &&
                        stack[stack.length - 1].name === RESOLVER_NAME.OPERATOR
                    ) {
                        const temp = stack.pop();

                        if (temp.name === RESOLVER_NAME.OPERATOR) {
                            postfix.push(temp);
                        }
                    }
                    stack.push(node);
                } else {
                    stack.push(node);
                }
            } else if (node.name === RESOLVER_NAME.GROUP) {
                // 如果是括号
                // 如果是")"
                if (afterTrigger) {
                    // 如果stack的栈顶不是"("
                    while (stack[stack.length - 1].name !== RESOLVER_NAME.GROUP && !stack[stack.length - 1].isStart) {
                        postfix.push(stack.pop());
                    }
                    // 弹出"("左括号
                    stack.pop();
                } else {
                    // 如果是"("
                    stack.push({
                        ...node,
                        isStart: true
                    });
                }
            } else if (node.name === RESOLVER_NAME.NUMBER || node.name === RESOLVER_NAME.CONDITION) {
                // 如果是数字或是条件
                postfix.push(node);
            }

            return accumulator;
        },
        {
            stack: [],
            postfix: []
        }
    );

    while (result.stack.length > 0) {
        result.postfix.push(result.stack.pop());
    }

    return result.postfix;
};

const print = (node1, operator, node2, result) => {
    console.log('------------------------------');
    console.log('node1:', node1);
    console.log('node2:', node2);
    console.log(`${getUnitFromStack(node1)} ${operator} ${getUnitFromStack(node2)} = ${result}`);
};

/**
 * 根据后缀表达式计算出单位结果
 * @param postfix
 * @returns {*}
 */
const calPostfix = postfix => {
    if (!postfix?.length) {
        return '';
    }

    const stack = [];

    for (let i = 0, { length } = postfix; i < length; i += 1) {
        const node = postfix[i];

        if (node.name === RESOLVER_NAME.OPERATOR) {
            const node2 = stack.pop();
            const node1 = stack.pop();

            let cal;

            switch (node.value) {
                case '+':
                    cal = unitAdd(getUnitFromStack(node1), getUnitFromStack(node2));
                    print(node1, '+', node2, cal);
                    break;

                case '-':
                    cal = unitMinus(getUnitFromStack(node1), getUnitFromStack(node2));
                    print(node1, '-', node2, cal);
                    break;

                case '*':
                    cal = unitMultiply(getUnitFromStack(node1), getUnitFromStack(node2));
                    print(node1, '*', node2, cal);
                    break;

                case '/':
                    cal = unitDivide(getUnitFromStack(node1), getUnitFromStack(node2));
                    print(node1, '/', node2, cal);
                    break;

                default:
                    throw new Error('error');
            }
            stack.push(cal);
        } else {
            stack.push(node);
        }
    }

    return getUnitFromStack(stack[0]);
};

const calFormulaUnit = formulaTree => {
    console.group('计算组合公式单位：');
    const postfix = treeToPostfix(formulaTree);
    console.log('postfix:', postfix);
    const treeUnit = calPostfix(postfix);
    console.log('------------------------------');
    console.log('treeUnit:', treeUnit);
    console.groupEnd();
    return treeUnit;
};

export default calFormulaUnit;
